package com.atguigu.krp.handler;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.extern.slf4j.Slf4j;

/**
 * @Description krp server heart beat handler
 * @author KEIO  on 2022/1/12.
 * @version 1.0
 */
@Slf4j
public class HeartBeatHandler extends ChannelInboundHandlerAdapter {

    //读超时是指     在指定时间内没有接收到任何数据
    //写超时是      指在指定时间内没有发送任何数据
    //将服务器端的读超时设置为60秒，客户端写超时设为50秒，客户端写超时则发送一个心跳包
    //因此服务器端与客户端如果正常连接则一定不会发生读超时
    //如果发生读超时则可能是网络延迟太高或者断线了，这时候就可以考虑断开连接了

    //读超时次数，超过指定次数则表示客户端离线或者网络不稳定，主动断开客户端连接
    private int waitCount = 1;
    private static final int MAX_WAIT_COUNT = 3;

    //连续超时间隔，80秒
    private static final long MAX_TIME_MILLIS_LIMIT = 60*1000;

    //上次读超时的时间，只有在一定时间范围内连续超时达到最大超时次数才表示客户端掉线
    //否则重置超时次数
    private long lastDisConnectTimeMillis = 0;

    //上次超时时间
    private long currentMillis = 0;



    //服务器读超时 默认调用的方法
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        currentMillis = System.currentTimeMillis();

        //两次超时时间间隔过长，重置超时次数与最后一次超时时间
        if((currentMillis - lastDisConnectTimeMillis) > MAX_TIME_MILLIS_LIMIT) {
            if(waitCount == 1) {
                waitCount ++;
                log.info("首次超时");
            } else {
                waitCount = 2;
                log.info("已重置超时次数和最后一次超时时间");
            }
        } else if (waitCount >= MAX_WAIT_COUNT) {

            ctx.channel().close();
            log.info("超时次数已经达到三次 断开与客户端的连接");

        } else {
            log.info("超时次数 {}", waitCount);
            waitCount++;
            lastDisConnectTimeMillis = currentMillis;

        }
    }


    //出现连接异常
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.channel().close();
        cause.printStackTrace();
        log.info("连接出现异常, 连接关闭");
    }
}
